package com.views
{
	import com.data.DecisionDAO;
	import com.events.ConnectEvent;
	import com.events.EditActivityEvent;
	import com.events.GraphEditEvent;
	import com.models.WorkFlow;
	
	import flash.display.DisplayObject;
	import flash.display.Sprite;
	import flash.events.MouseEvent;
	import flash.text.TextField;
	import flash.text.TextFieldAutoSize;
	
	import mx.core.DragSource;
	import mx.core.UIComponent;
	import mx.effects.Tween;
	import mx.events.TweenEvent;
	import mx.effects.easing.Bounce;
	import mx.events.DragEvent;
	import mx.managers.DragManager;

	/**
	 * Klasse zur Darstellung einer Entscheidung im Graphen
	 */
	public class Decision extends UIComponent implements IGraphElement
	{
		
		private var _currentIcon:DisplayObject;
		private var _displayTaskLabel:TextField;
		private var _labelChanged:Boolean = false;
		private var _label:String;
		private var _model:WorkFlow;
		private var _background:Sprite;
		private var _bgrdChanged:Boolean = false;
		private var _padding:int = 5;
		private var _connect:Boolean = false;
		private var _dataId:String;
		private var _selected:Boolean;
		private var _delBorder:Sprite;
		
		/**
		 * Konstruktor
		 * @param model Referenz auf das Model
		 * 
		 */
		public function Decision(model:WorkFlow, data:DecisionDAO)
		{
			_model = model;
			_dataId = data.dataId;
			toolTip = data.dataId;
			_model.setView(this);
		}
		
		/**
		 * Hinzufügen der grundlegenden Elemente dieser Klasse.
		 * Wird genau einmal aufgerufen, dies findet während der
		 * Instanzierung statt.
		 */
		override protected function createChildren():void
		{
			super.createChildren();
			
			if(_displayTaskLabel == null)
			{
				_displayTaskLabel = new TextField();
			}
			
			_displayTaskLabel.multiline = true;
			_displayTaskLabel.wordWrap = true;
			_background = drawRect(100,50);
			addChild(_background);
			//_displayTaskLabel.width = 300;
			//_displayTaskLabel.height = 300;
			_displayTaskLabel.autoSize = TextFieldAutoSize.CENTER;
			addChild(_displayTaskLabel);
			
			
			addListeners();
			
			this.label = "Bedingung";
		}
		
		/**
		 * Aktualisierung der Eigenschaften der Elemente dieser Klasse.
		 * Wird auch bei der Instanzierung aufgerufen.
		 */
		override protected function commitProperties():void
		{
			super.commitProperties();
			
			if(_labelChanged) 
			{
				_labelChanged = false;
				_displayTaskLabel.text = _label;
				_bgrdChanged = true;
			}
		}
		
		/**
		 * Text der Entscheidung
		 * @param value
		 * 
		 */
		public function set label(value:String):void
		{
			_label = value;
			_labelChanged = true;
			
			invalidateProperties();
			invalidateDisplayList();
		}
		
		/**
		 * Eindeutiger Identifizierer
		 * @return 
		 * 
		 */
		public function get dataId():String
		{
			return _dataId;
		}
		
		public function get background():Sprite
		{
			return _background;
		}
		
		
		/**
		 * Hinzufügen der EventListener
		 */
		protected function addListeners():void
		{
			addEventListener(EditActivityEvent.EDIT, editHandler);
			addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
			addEventListener(DragEvent.DRAG_DROP, dragDropHandler);
			addEventListener(DragEvent.DRAG_ENTER, dragEnterHandler);
			addEventListener(DragEvent.DRAG_EXIT, dragExitHandler);
			addEventListener(MouseEvent.ROLL_OVER, rollOverHandler);
			addEventListener(MouseEvent.ROLL_OUT, rollOutHandler);
			_model.addEventListener(ConnectEvent.UPDATE, connectUpdateHandler);
			_model.addEventListener(GraphEditEvent.UPDATE, graphEditUpdateHandler);
		}
		/**
		 * Entfernen der EventListener
		 */
		protected function removeListeners():void
		{
			removeEventListener(EditActivityEvent.EDIT, editHandler);
			removeEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
		}
		
		/**
		 * Behandlung der EditActivityEvents
		 * @param evt EditActivityEvent
		 * 
		 */
		protected function editHandler(evt:EditActivityEvent):void
		{
			
		}
		
		/**
		 * Zeichnet ein Rechteck
		 * @param width Breite des Rechtecks
		 * @param height Höhe des Rechtecks
		 * @return Rückgabe des Rechtecks als Sprite
		 * 
		 */
		protected function drawRect(width:int, height:int):Sprite
		{
			var thickness:int = 2;
			var lineColor:uint = 0xCCCCCC;
			var selectedColor:uint = 0xCC0000;
			
			var sprite:Sprite = new Sprite();
			sprite.graphics.lineStyle(thickness, lineColor, 1);
			sprite.graphics.beginFill(0xCCCCCC, 0.5);
			var side:int = height < width ? width : height;
			var corner:int = side / 4;
			// TODO Quadrat und rotieren
			sprite.graphics.drawRoundRect(0, 0, side, side, corner, corner);
			sprite.rotation = 45;
			sprite.transform.pixelBounds
			sprite.graphics.endFill();
			if(_selected)
			{
				sprite.graphics.lineStyle(thickness, selectedColor, 0.5);
				corner = height < width ? height / 4 : width / 4;
				sprite.graphics.drawRoundRect(-5, -5, side+10, side+10, corner, corner);
			}
			
			return sprite;
		}
		
		/**
		 * @
		 * @param unscaledWidth
		 * @param unscaledHeight
		 * 
		 */
		override protected function updateDisplayList(
			unscaledWidth:Number, 
			unscaledHeight:Number):void
		{
			super.updateDisplayList(unscaledWidth, unscaledHeight);
			
			if(_bgrdChanged)
			{
				_bgrdChanged = false;
				removeChild(_background);
				var txtWidth:int = _displayTaskLabel.textWidth;
				var txtHeight:int = _displayTaskLabel.textHeight;
				_background = drawRect(
					txtWidth + _padding,
					txtHeight + _padding);
				var side:int = txtWidth < txtHeight ? txtHeight + _padding : txtWidth + _padding;
				var diagonal:int = side*Math.sqrt(2);
				
				_displayTaskLabel.width = _displayTaskLabel.textWidth + 5;
				_displayTaskLabel.height = _displayTaskLabel.textHeight + 5;
				// TODO label richtig ausrichten
				_displayTaskLabel.x = -diagonal/3
				_displayTaskLabel.y = diagonal/3 + 5;
				width = _background.width;
				height = _background.height;
				addChild(_background);
			}
			
		}
		
		/**
		 * Behandlung des MouseDown Events
		 * @param evt
		 * 
		 */
		protected function mouseDownHandler(evt:MouseEvent):void
		{
			var dragSource:DragSource = new DragSource();
			dragSource.addData(this, "decision");
			var dragInitiator:UIComponent = evt.currentTarget as UIComponent;
			var offsetX:int = dragInitiator.mouseX;
			var offsetY:int = dragInitiator.mouseY;
			dragSource.addData(offsetX, 'offsetX');
			dragSource.addData(offsetY, 'offsetY');
			var proxy:UIComponent = new DecisionProxy(
				_displayTaskLabel.textWidth + _padding,
				_displayTaskLabel.textHeight + _padding);
			_model.proxy = proxy as UIComponent;
			proxy.alpha = .75;
			dragSource.addData(proxy, "proxy");
			DragManager.doDrag(this, dragSource, evt, proxy);
			_model.setSelectedElement(this);
		}
		
		/**
		 * Behandlung des DragEnter Events
		 * @param evt
		 * 
		 */
		protected function dragEnterHandler(evt:DragEvent):void
		{
			if(evt.dragSource.hasFormat("activity"))
			{
				var target:Decision = Decision(evt.currentTarget);
				DragManager.acceptDragDrop(target);
				var initiator:Activity = Activity(evt.dragInitiator);
				initiator.connect = true;
				initiator.visible = true;
			}
		}
		
		/**
		 * Behandlung des DragDrop Events
		 * @param evt
		 * 
		 */
		protected function dragDropHandler(evt:DragEvent):void
		{
			if(evt.dragSource.hasFormat("activity"))
			{
				var initiator:Activity = Activity(evt.dragInitiator);
				var target:IGraphElement = IGraphElement(evt.currentTarget);
				initiator.connect = false;
				initiator.visible = true;
				_model.addConnection(initiator, target);
			}
		}
		
		/**
		 * Behandlung des DragExit Events
		 * @param evt
		 * 
		 */
		protected function dragExitHandler(evt:DragEvent):void
		{
			if(evt.dragSource.hasFormat("activity"))
			{
				var initiator:Activity = Activity(evt.dragInitiator);
				
				initiator.visible = false;
				initiator.connect = false;
				
				
			}
		}
		
		/**
		 * Behandlung des ConnectUpdate Events
		 * @param evt
		 * 
		 */
		protected function connectUpdateHandler(evt:ConnectEvent):void
		{
			
		}
		
		private function graphEditUpdateHandler(evt:GraphEditEvent):void
		{
			if(_dataId == evt.data.dataId)
				label = evt.data.text;
		}
		
		private function mouseClickHandler(evt:MouseEvent):void
		{
			//_model.setSelectedElement(this);
		}
		
		public function rollOverHandler(evt:MouseEvent):void
	    {
	    	if(_model.tool == "delete")
	    	{
		    	var thickness:int = 2;
				var lineColor:uint = 0x0055FF;
				var selectedColor:uint = 0xCC0000;
		    	
		    	_delBorder = new Sprite();
				_delBorder.graphics.lineStyle(thickness, selectedColor, 1);
				var side:int = height < width ? width : height;
				_delBorder.graphics.drawCircle(side/2, side/2, side/2+40);
				_delBorder.rotation = 45;
				_delBorder.x = 0;
				_delBorder.y = 0;
				_delBorder.alpha = 0.5;
				var tween:Tween = new Tween(this, side + 60, 2*(side/2+40), 500);
		    	tween.easingFunction = mx.effects.easing.Bounce.easeOut;
				addChild(_delBorder);
	    	}
	    }
	    
	    public function rollOutHandler(evt:MouseEvent):void
	    {
	    	if(_delBorder)
	    	{
	    		removeChild(_delBorder);
	    		_delBorder = null;
	    	}
	    }
	    
	    public function onTweenUpdate(val:int):void
	    {
	    	if(_delBorder)
	    	{
		    	_delBorder.width = val;
		    	_delBorder.height = val;
	    	}
	    }
	    public function onTweenEnd(val:int):void
	    {
	    	
	    }
		
		/**
		 * Status zur Bestimmung des Aktionszustandes.
		 * Wenn die gerade ausgeführte Aktion zu der Erzeugung 
		 * einer neuen Verbindung führt ist dieser Wert true.
		 * @return 
		 * 
		 */
		public function get connect():Boolean
		{
			return _connect;
		}
		public function set connect(value:Boolean):void
		{
			_connect = value;
			trace("Decision is connecting");
		}
		
		public function get selected():Boolean
		{
			return _selected;
		}
		public function set selected(value:Boolean):void
		{
			_selected = value;
			_bgrdChanged = true;
			invalidateDisplayList();
		}
	}
}